﻿/* app_ifft_example.c */

#include "app.h"
#include "app_fft_data.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/
/*
* CMSIS-DSP
*/
/* cmsis-dsp 浮点数FFT逆变换. */
void app_arm_ifft_f32_example(void)
{
    PRINTF("%s()\r\n", __func__);
    /* 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_f32(fft_input_f32, FFT_INPUT_NUM_512);

    /* 正变换. */
    arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_input_f32, 0, 0);

    TimerCount_Start(); /* 开始计时. */

    /* 逆变换. */
    arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_input_f32, 1, 0);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    /* 打印计算结果. */
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %f, %f\r\n", i, fft_input_f32[i*2], fft_input_f32[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

/* cmsis-dsp q31定点数FFT逆变换. */
void app_arm_ifft_q31_example(void)
{
    PRINTF("%s()\r\n", __func__);
    /* 以复数方式填充, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q31(fft_input_q31, FFT_INPUT_NUM_512);

    /* 定点数FFT会将输入输入除以N, 定点数FFT逆变换会将输入再除以N.
     * FFT逆变换除以N是正常的, FFT正变换除以N是为了简化算法实现(这样可以使用统一的过程同时实现正变换和逆变换的计算)
     * 将原始输入信号放大N倍是为了抵消FFT正变换除以N的缩放效果.
     * 此处将原始输入信号放大N * N, 是为了放大输出序列为预期的N倍, 从而在允许误差的情况下看到有效的输出信号,
     * 否则可能在非常粗糙的量化机制下, 很多有效信号都会被向下取整的除法运算损失有效数字.
     */
    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512*2; i++)
    {
        fft_input_q31[i] *= (FFT_INPUT_NUM_512* FFT_INPUT_NUM_512);
    }

    /* 正变换. */
    arm_cfft_q31(&arm_cfft_sR_q31_len512, fft_input_q31, 0, 1);
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }

    PRINTF("press any key to continue ...\r\n");
    GETCHAR();

    TimerCount_Start(); /* 开始计时. */
    /* 逆变换 */
    arm_cfft_q31(&arm_cfft_sR_q31_len512, fft_input_q31, 1, 1);
    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

void app_arm_ifft_q15_example(void)
{
    PRINTF("%s()\r\n", __func__);
    /* 以复数方式填充, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q31(fft_input_q31, FFT_INPUT_NUM_512);

    /* 16位数的内存空间不能经受N*N, 因此将第二次N放在fft逆变换之前. */
    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512*2; i++)
    {
        fft_input_q31[i] *= FFT_INPUT_NUM_512;
    }

    /* 正变换. */
    arm_cfft_q31(&arm_cfft_sR_q31_len512, fft_input_q31, 0, 1);
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }

    PRINTF("press any key to continue ...\r\n");
    GETCHAR();

    /* 16位数的内存空间不能经受N*N, 因此将第二次N放在fft逆变换之前.
     * 注意, 逆变换中乘以N不是必须的, 此处乘以N仅仅为了在整数范围中看到本来在小数点右边的计算误差.
     */
    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512*2; i++)
    {
        fft_input_q31[i] *= FFT_INPUT_NUM_512;
    }

    TimerCount_Start(); /* 开始计时. */

    /* 逆变换 */
    arm_cfft_q31(&arm_cfft_sR_q31_len512, fft_input_q31, 1, 1);
    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

/*
* PowerQuad.
*/
/* PowerQuad q31定点数算FFT逆变换. */
void app_pq_ifft_q31_example(void)
{
    pq_config_t pq_config;
    PRINTF("%s()\r\n", __func__);

    /* 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q31(fft_input_q31, FFT_INPUT_NUM_512);

    /* 执行定点数FFT: input_q31 -> output_q31. */
    pq_config.inputAFormat = kPQ_32Bit; /* 以32位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* 乘以512以抵消FFT算法中除以N的影响 */
    pq_config.outputFormat = kPQ_32Bit; /* 以32位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_TransformCFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_input_q31,
        fft_output_q31);
    PQ_WaitDone(POWERQUAD);

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_output_q31[i*2], fft_output_q31[i*2+1]);
    }

    PRINTF("press any key to continue ...\r\n");
    GETCHAR();

    /* 将原来的输入数组清除. */
    memset(fft_input_q31, 0, FFT_INPUT_NUM_512*2*sizeof(q31_t));

    TimerCount_Start(); /* 开始计时. */

    /* 执行定点数FFT: input_q31 -> output_q31. */
    pq_config.inputAFormat = kPQ_32Bit; /* 以32位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* FFT逆变换本来就要除以N, 此处不需要抵消除法的效果了. 这里仍放大N倍是为了将输出放大, 输出的scale设置在当前硬件版本中不起作用. */
    pq_config.outputFormat = kPQ_32Bit; /* 以32位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_TransformIFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_output_q31,
        fft_input_q31);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}


/* PowerQuad q15定点数算FFT逆变换. */
void app_pq_ifft_q15_example(void)
{
    pq_config_t pq_config;
    PRINTF("%s()\r\n", __func__);

    /* 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q15(fft_input_q15, FFT_INPUT_NUM_512);

    /* 执行定点数FFT: input_q15 -> output_q15. */
    pq_config.inputAFormat = kPQ_16Bit; /* 以32位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* 乘以512以抵消FFT算法中除以N的影响 */
    pq_config.outputFormat = kPQ_16Bit; /* 以32位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_TransformCFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_input_q15,
        fft_output_q15);
    PQ_WaitDone(POWERQUAD);

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_output_q15[i*2], fft_output_q15[i*2+1]);
    }

    PRINTF("press any key to continue ...\r\n");
    GETCHAR();

    /* 将原来的输入数组清除. */
    memset(fft_input_q15, 0, FFT_INPUT_NUM_512*2*sizeof(q15_t));

    TimerCount_Start(); /* 开始计时. */

    /* 执行定点数FFT: input_q15 -> output_q15. */
    pq_config.inputAFormat = kPQ_16Bit; /* 以32位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* FFT逆变换本来就要除以N, 此处不需要抵消除法的效果了. 这里仍放大N倍是为了将输出放大, 输出的scale设置在当前硬件版本中不起作用. */
    pq_config.outputFormat = kPQ_16Bit; /* 以32位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_TransformIFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_output_q15,
        fft_input_q15);
    PQ_WaitDone(POWERQUAD);
    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q15[i*2], fft_input_q15[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

#if 0 /* SDK的原始测试用例. */
#define DEMO_POWERQUAD POWERQUAD

#define MATH_PI 3.1415926535898
#define FLOAT_2_Q31(x) ((int32_t)((x)*2147483648.0f))
#define FLOAT_2_Q15(x) (int16_t) __SSAT(((int32_t)((x)*32768.0f)), 16)

#define RFFT_INPUT_LEN 128
#define CFFT_INPUT_LEN 128
#define IFFT_INPUT_LEN 128
#define DCT_INPUT_LEN 128

#define FIR_INPUT_LEN 16
#define FIR_TAP_LEN 12

#define CONV_A_LEN 5
#define CONV_B_LEN 5
#define CONV_RESULT_LEN (CONV_A_LEN + CONV_B_LEN - 1)

#define CORR_A_LEN 5
#define CORR_B_LEN 5
#define CORR_RESULT_LEN (CORR_A_LEN + CORR_B_LEN - 1)

#define EXAMPLE_ASSERT_TRUE(x)            \
    if (!(x))                             \
    {                                     \
        PRINTF("%s error\r\n", __func__); \
        while (1)                         \
        {                                 \
        }                                 \
    }

#define PQ_SET_FIX32_CONFIG                                                                 \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_FIX16_CONFIG                                                                 \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_Q31_CONFIG                                                                     \
    POWERQUAD->OUTFORMAT = ((uint32_t)(-31) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float;   \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float;   \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float;   \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_Q15_CONFIG                                                                     \
    POWERQUAD->OUTFORMAT = ((uint32_t)(-15) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float;   \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float;   \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float;   \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_F32_CONFIG                                                                   \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_FFT_Q31_CONFIG                                                               \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_FFT_Q15_CONFIG                                                               \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_32Bit; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_MAT_FIX32_WORKAROUND_SCALE_CONFIG                                            \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_MAT_FIX32_WORKAROUND_MULT_CONFIG                                             \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_32Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_MAT_FIX16_WORKAROUND_SCALE_CONFIG                                            \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->INAFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->TMPFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

#define PQ_SET_MAT_FIX16_WORKAROUND_MULT_CONFIG                                             \
    POWERQUAD->OUTFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_16Bit << 4U) | kPQ_Float; \
    POWERQUAD->INBFORMAT = ((uint32_t)(0) << 8U) | ((uint32_t)kPQ_Float << 4U) | kPQ_Float; \
    POWERQUAD->TMPBASE = 0xE0000000

void arm_cfft_q31_sb(const arm_cfft_instance_q31 *S, q31_t *p1, uint8_t ifftFlag, uint8_t bitReverseFlag)
{
    assert(bitReverseFlag == 1);

    q31_t *pIn = p1;
    q31_t *pOut = p1;
    uint32_t length = S->fftLen;

    PQ_SET_FFT_Q31_CONFIG;

    if (ifftFlag == 1U)
    {
        PQ_TransformIFFT(POWERQUAD, length, pIn, pOut);
    }
    else
    {
        PQ_TransformCFFT(POWERQUAD, length, pIn, pOut);
    }

    PQ_WaitDone(POWERQUAD);
}


/* Q31 IFFT */
void arm_ifft_q31Example(void)
{
    q31_t inout[FFT_INPUT_NUM_512 * 2] = {0};
    //q31_t ref[FFT_INPUT_NUM_512 * 2];
    arm_cfft_instance_q31 instance = {.fftLen = FFT_INPUT_NUM_512};

    /* Reference result: Two full period sin wave. */
    /*
     * Number of bits to upscale = log2(input data size) - 1. Here the input
     * data is 2*128 = 256, so upscale bits is 7.
     */
#if 0
    /*
     * Because only low 27 bits could be used for FFT, the input data
     * should left shift 5 bits to ensure no saturation.
     */
    for (uint32_t i = 0; i < IFFT_INPUT_LEN / 2; i++)
    {
        ref[i * 2]     = ((arm_sin_q31(i * (0x80000000 / (IFFT_INPUT_LEN / 2))) / 2) >> 7) >> 5;
        ref[i * 2 + 1] = ((arm_cos_q31(i * (0x80000000 / (IFFT_INPUT_LEN / 2))) / 2) >> 7) >> 5;
    }
    memcpy(&ref[IFFT_INPUT_LEN], ref, sizeof(ref) / 2);
#endif
    /* Input. */
    //inout[253] = FLOAT_2_Q31(0.5f / 32.0f); /* Imag(126) */

    //inout[0] = 768*1024;
    inout[512] = -256*1024*1024;


    arm_cfft_q31_sb(&instance, inout, 1, 1);

    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        //EXAMPLE_ASSERT_TRUE(abs(inout[i] - ref[i]) <= 1);
      PRINTF("[%3d]: %d, %d\r\n", i, inout[i*2], inout[i*2+1]);

    }
}
#endif

/* EOF. */

